using System;
using Microsoft.SPOT;
using nRF24L10P.Helper;

namespace nRF24L10P
{
    public class DeviceConfig
    {
        nRF24L10P device;
        public enum NRFDataRate
        {
            DR1Mbps,
            DR2Mbps,
            /// <summary>
            /// Warning: 250kbps is for comtability only, it will cause send fail when autoACK is on
            /// </summary>
            DR250kbps,
        }

        public enum RadioPowerEnum:byte
        {
            /// <summary>
            /// 0dBm    RF_PWR=11
            /// </summary>
            High=3,
            /// <summary>
            /// -6dBm   RF_PWR=10
            /// </summary>
            Normal=2,
            /// <summary>
            /// -12dBm  RF_PWR=01
            /// </summary>
            Low=1,
            /// <summary>
            /// -18dBm  RF_PWR=00
            /// </summary>
            VeryLow=0
        }

        public enum CRCEncodingSchemeEnum
        {
            SingleByte=0,
            DualBytes=1
        }

        public enum AutoRetransmitDelayEnum:byte
        {
            Delay250uS = 0,
            Delay500uS = 1,
            Delay750uS = 2,
            Delay1000uS = 3,
            Delay1250uS = 4,
            Delay1500uS = 5,
            Delay1750uS = 6,
            Delay2000uS = 7,
            Delay2250uS = 8,
            Delay2500uS = 9,
            Delay2750uS = 10,
            Delay3000uS = 11,
            Delay3250uS = 12,
            Delay3500uS = 13,
            Delay3750uS = 14,
            Delay4000uS = 15
        }


        public DeviceConfig(nRF24L10P device)
        {
            this.device = device;
        }

        public NRFDataRate DataRate
        {
            get 
            {
                bool low = device.Registers.RF_SETUP.RF_DR_LOW;
                bool high = device.Registers.RF_SETUP.RF_DR_HIGH;
                if (!low & !high)
                {
                    return NRFDataRate.DR1Mbps;
                }
                if (low & !high)
                {
                    return NRFDataRate.DR250kbps;
                }
                if (!low & high)
                {
                    return NRFDataRate.DR2Mbps;
                }
                throw new InvalidOperationException("Error data rate detected");
            }
            set 
            {
                switch (value)
                {
                    case NRFDataRate.DR1Mbps:
                        device.Registers.RF_SETUP.RF_DR_LOW = false;
                        device.Registers.RF_SETUP.RF_DR_HIGH = false;
                        break;
                    case NRFDataRate.DR2Mbps:
                        device.Registers.RF_SETUP.RF_DR_LOW = false;
                        device.Registers.RF_SETUP.RF_DR_HIGH = true;
                        break;
                    case NRFDataRate.DR250kbps:
                        device.Registers.RF_SETUP.RF_DR_LOW = true;
                        device.Registers.RF_SETUP.RF_DR_HIGH = false;
                        break;
                    default:
                        throw new InvalidOperationException("Invalid data rate value");
                }
                device.Registers.RF_SETUP.Save();
            }
        }


        public RadioPowerEnum RadioPower
        {
            get 
            {
                byte tmp= device.Registers.RF_SETUP.RF_PWR;
                return (RadioPowerEnum)tmp;
            }
            set 
            {
                device.Registers.RF_SETUP.RF_PWR = (byte)value;
                device.Registers.RF_SETUP.Save();
            }
        }

        public bool CRCEnabled
        {
            get
            {
                return device.Registers.CONFIG.EN_CRC;
            }
            set
            {
                device.Registers.CONFIG.EN_CRC = true;
                device.Registers.CONFIG.Save();
            }
        }

        public CRCEncodingSchemeEnum CRCEncodingScheme
        {
            get 
            {
                return device.Registers.CONFIG.CRCO ? CRCEncodingSchemeEnum.DualBytes : CRCEncodingSchemeEnum.SingleByte;
            }
            set
            {
                device.Registers.CONFIG.CRCO = (value == CRCEncodingSchemeEnum.DualBytes);
                device.Registers.CONFIG.Save();
            }
        }

        
        public AutoRetransmitDelayEnum AutoRetransmitDelay
        {
            get
            {
                return (AutoRetransmitDelayEnum)device.Registers.SETUP_RETR.ARD;
            }
            set
            {
                device.Registers.SETUP_RETR.ARD = (byte)value;
                device.Registers.SETUP_RETR.Save();
            }
        }


        /// <summary>
        /// setting this value to 0 will disable auto retransmit
        /// </summary>
        public byte AutoRetransmitCount
        {
            get 
            {
                return device.Registers.SETUP_RETR.ARC;
            }
            set
            {
                if (value>15)
                {
                    throw new ArgumentOutOfRangeException("AutoRetransmitCount", "AutoRetransmitCount should be 0 - 15");
                }
                device.Registers.SETUP_RETR.ARC = value;
                device.Registers.SETUP_RETR.Save();
            }
        }

        public uint RadioChannel
        {
            get 
            {
                return (uint)device.Registers.RF_CH.RF_CH; 
            }
            set 
            {
                if (RadioChannel>125)
                {
                    throw new ArgumentOutOfRangeException("Channel", "Channel should be 0 - 125");
                }
                device.Registers.RF_CH.RF_CH = (byte)value;
                device.Registers.RF_CH.Save();
            }
        }

        public int AddressWidth
        {
            get
            {
                switch ((int)device.Registers.SETUP_AW.AW)
                {
                    case 1:
                        return 3;   //01 = 3 bytes
                    case 2:
                        return 4;   //10 = 4 bytes
                    case 3:
                        return 5;   //11 = 5 bytes
                    default:
                        throw new InvalidOperationException("Error reading registry value SETUP_AW.AW");
                }
            }
            set
            {
                switch (value)
                {
                    case 3:
                        device.Registers.SETUP_AW.AW = (byte)1;
                        break;
                    case 4:
                        device.Registers.SETUP_AW.AW = (byte)2;
                        break;
                    case 5:
                        device.Registers.SETUP_AW.AW = (byte)3;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException("AddressWidth", "AddressWidth should be 3,4,5 only");
                }
                device.Registers.SETUP_AW.Save();
            }
        }

        public bool DynamicPayloadLengthEnabled
        {
            get
            {
                return device.Registers.FEATURE.EN_DPL;
            }
            set
            {
                device.Registers.FEATURE.EN_DPL = value;
                device.Registers.FEATURE.Save();
            }
        }
    }
}
